Repository navigation
Conversation
There was a problem hiding this comment.
I couldn't run the panel: it only exists in the web/desktop app, and this environment has no browser (only the TUI can be driven here). Could you attach a couple of screenshots or a short video of the Media tab and the gallery viewer?
The new collect tests and the full gui-plugins suite pass, and so do the ui image tests. tsc is clean in gui-plugins, ui, schema and session-ui. From reading the code, the flag check mirrors Core's Flag.resolve order, and existing ImagePreview callers work as before. I found no blocking issues.
Public API, all backwards compatible:
- Adds the optional boolean config key
experimental.session_media(config schema, OpenAPI spec and generated client types). - Adds a new
@opencode/session-ui/sources/site-iconexport. - Adds two optional props,
positionandonStep, toImagePreview.
One thing to keep in mind: enabled() in media/renderer.tsx is an app-side copy of Core's flag resolution and can't see OPENCODE_FLAGS. If more app features get flags, the server could expose resolved flags so the two can't drift.
Related: #58295
There was a problem hiding this comment.
The new commit only changes how the Files and Links lists look (rows grouped by day, a shared row layout, who-did-what labels and the item's folder or address), and I found nothing new to flag. bun test src/media and tsc -b in packages/gui-plugins both pass. I couldn't render the panel here because there's no browser in this environment. A screenshot of the new file and link rows would help reviewers.
The public API is the same as in the last review. This commit only touches the plugin's UI, CSS and English strings.
There was a problem hiding this comment.
The new commit replaces the "Load earlier messages" button with automatic loading as the panel scrolls. bun test src/media and tsc -b in packages/gui-plugins pass. I couldn't watch the scroll behaviour here because there's no browser in this environment.
One concern is worth fixing: when the open tab has few or no items, the automatic loading never stops until the session's whole history is in the app's message store (see the inline comment). The public API hasn't changed since the last review.
|
|
||
| // Syncs with the server: one page at a time while the end is visible, so it stops once a page pushes the end off | ||
| // screen, the history ends, or a load fails. | ||
| createKeyed(() => end() && more() && !loading() && !failed() && `${props.session.id}:${settled()}`, page) |
There was a problem hiding this comment.
All three tabs read the same messages. If the open tab has few or no items (say Links in a session without links), the end marker never scrolls off screen, so this keeps calling loadMore until more() is false. In a long session, just opening the panel pulls the whole history into the app's shared message store, which works against the app keeping only recent messages and puts that history into the store the timeline also uses. Could automatic loading stop after a few pages, or only run when the user scrolls, with a button for the rest?
Separately, failed doesn't seem to reset when props.session changes. If so, after an error the next session won't load older messages until "Try again" is clicked.
There was a problem hiding this comment.
Reverting the automatic loading addresses my earlier concern: the panel only loads older messages when "Load older" is clicked, so opening it can't pull a session's whole history into memory, and the failed state that didn't reset between sessions is gone with it. bun test src/media and tsc -b in packages/gui-plugins pass. I couldn't render the panel here because there's no browser in this environment. Nothing new to raise, and the public API hasn't changed since the last review.
The Media panel now lists a session's images, videos and links through an experimental.media RPC served by a built-in plugin behind session_media, paging the whole history newest first instead of reading the timeline's loaded messages. Links group by site or GitHub repository with search, the Files tab is gone, and the panel keeps its tab and sender filter per session.
There was a problem hiding this comment.
Reading the session's media through the new server RPC addresses my earlier concern. Older pages come from experimental.media.list into the panel's own history, so the end-of-list loading no longer fills the timeline's message store, and the failure flag starts fresh with each session's history. The new collect tests in packages/core and the link-groups test in packages/gui-plugins pass, and tsc is clean in core, gui-plugins and schema. I couldn't render the panel here because there's no browser in this environment, so a short video of the links view, search and paging would help.
Public API changes since the last review, all backwards compatible:
- Adds the
experimental.mediaRPC with alist({ sessionID, cursor?, limit? })method, marked experimental and registered only whensession_mediais on. - Adds a new
@opencode/schema/session-mediamodule with theSource,Media,LinkandPageschemas. - Removes the
@opencode/session-ui/sources/site-iconexport that earlier versions of this pull request added.
The experimental.session_media config key and the ImagePreview position and onStep props are unchanged. Nothing new to raise.
Summary
Adds a Media tab to the session side panel that lists the images, videos and links shared in a session, by you or the agent, so you can find a screenshot or a link without scrolling the conversation. It covers the whole session, not just the messages the timeline has loaded.
#123chips, and other pages as title chips. Hovering a chip shows the full title, the address, who shared it and when. Clicking opens the in-app browser, or the system browser when that isn't available. Icons work like the timeline's links: GitHub's mark, a public site's favicon, and a globe for private hosts such aslocalhost, which are never sent to the favicon service.Implementation
Server: a built-in plugin,
packages/core/src/plugin/media.ts, registered next togoal. It serves anexperimental.mediaRPC whoselistmethod reads a page of a session's messages from the database, newest first, and returns only the images, videos and links in them, plus a cursor for the next page. Pages never include file bytes. The extraction is inmedia/collect.ts, with tests inpackages/core/test/plugin/media.test.ts. The RPC definition and item schemas are inpackages/schema/src/session-media.ts.App: the built-in GUI plugin in
packages/gui-plugins/src/media/.history.tspages the RPC: 200 messages on the first read, 200 more each time older history is needed, and the 50 newest whenever the timeline's last message changes (a new message, a tool finishing, a reply ending). It doesn't read message contents from the timeline or make the timeline load older history.source.tsloads each card's bytes once it's visible: stored media throughexperimental.media.get, files by path throughfile.read, and inline bytes from their message.link-groups.tsgroups the links, with tests.links.tsxrenders the groups.ImagePreview(packages/ui) gains two optional props,positionandonStep, for stepping through a set. It now remembers which origin it hid, so stepping to another image shows the thumbnail it left. Existing callers pass neither prop and behave as before.Feature flag
Guarded by the new
session_mediaflag inpackages/schema/src/config/flag.ts. It is on in local and dev builds and off in releases. When the flag is off, the server doesn't register the RPC, and the app closes the tab and hides the + menu item and the "Open media" command.The app reads the flag from the session directory's config the same way Core resolves it:
experimental.session_media, thenexperimental.all_flags, then the build channel. It can't seeOPENCODE_FLAGS, which only the server reads.Not included
Testing
bun run checkpasses, plusbun test src/mediainpackages/gui-plugins, the media plugin tests inpackages/core, and the image tests inpackages/ui.Visual
Added by the opencode bot (AI-generated).
Related: #58295
Public API: adds the experimental.session_media flag, an experimental
experimental.mediaRPC with its @opencode/schema/session-media schemas, and optional ImagePreview position/onStep props (backwards compatible)